<template>
	<view class="e-calendar" :style="customStyle">
		<eHeader :date="myDate" :format="props.format" :sundayStart="props.sundayStart" @monthChange="monthChange">
		</eHeader>
		<e-calendar-month ref="monthRef" :format="props.format" :rowHeight="props.rowHeight" :mode="props.mode"
			:maxCount="props.maxCount" :startText="props.startText" :endText="props.endText"
			:sundayStart="props.sundayStart" :defaultDate="props.defaultDate" :minDate="innerMinDate"
			:maxDate="innerMaxDate" :readonly="props.readonly" :maxRange="props.maxRange"
			:rangePrompt="props.rangePrompt" :fold="expanded" :showRangePrompt="props.showRangePrompt"
			:showNowDateDot="props.showNowDateDot" :markDateMore="props.markDateMore" @monthSelected="monthSelected"
			@changeMonth="changeMonth">
		</e-calendar-month>
		<slot name="footer">
		</slot>
	</view>
</template>
<script lang="ts">
	import {
		defineComponent
	} from 'vue'
	import mpMixin from "../../libs/mixin/mpMixin";
	/**
	 * Calendar 日历
	 * @description  此组件用于单个选择日期，范围选择日期等，日历被包裹在底部弹起的容器中.
	 * @tutorial https://www.uviewui.com/components/calendar.html
	 *
	 * @property {String}				mode				日期类型选择  single-选择单个日期，multiple-可以选择多个日期，range-选择日期范围 （ 默认 'single' )
	 * @property {String}				startText			mode=range时，第一个日期底部的提示文字  (默认 '开始' )
	 * @property {String}				endText				mode=range时，最后一个日期底部的提示文字 (默认 '结束' )
	 * @property {String}				color				主题色，对底部按钮和选中日期有效  (默认 ‘#3c9cff' )
	 * @property {String | Number}		minDate				最小的可选日期	 (默认 0 )
	 * @property {String | Number}		maxDate				最大可选日期  (默认 7258089600000 )
	 * @property {Array | String| Date}	defaultDate			默认选中的日期
	 * @property {String | Number}		maxCount			mode=multiple时，最多可选多少个日期  (默认 	Number.MAX_SAFE_INTEGER  )
	 * @property {String | Number}		rowHeight			日期行高 (默认 56 )
	 * @property {String}				format				header的日期格式 默认为yyyy-mm
	 * @property {Boolean}				showLunar			是否显示农历  (默认 false )
	 * @property {Boolean}				readonly	        是否为只读状态，只读状态下禁止选择日期 (默认 false )
	 * @property {String | Number}		maxRange	        日期区间最多可选天数，默认无限制，mode = range时有效
	 * @property {String}				rangePrompt	        范围选择超过最多可选天数时的提示文案，mode = range时有效
	 * @property {Boolean}				showRangePrompt	    范围选择超过最多可选天数时，是否展示提示文案，mode = range时有效 (默认 true )
	 * @property {Boolean}				allowSameDay	    是否允许日期范围的起止时间为同一天，mode = range时有效 (默认 false )
	 * @property {Boolean}				sundayStart	    	是否默认从周日开始 (默认 false )
	 * @property {string}				nowDate	    		当前日期(默认 new Date() )
	 * @property {Boolean}				showNowDateDot	    显示今天日期上的小圆点
	 * @property {Array}				markDateMore	    给指定日期添加自定义的class
	 * @property {Boolean}				conversion			mode=range时,是否转换返回的数据列表，不开启时，返回的列表格式为[startDate,endDate],开启则会将列表转换为长度等同于所选日期间隔天数，每一项为对应日期的数据格式
	 * @property {Object}	    		customStyle					自定义样式
	 *
	 * @event {Function()} confirm 		点击确定按钮时触发		选择日期相关的返回参数
	 * @event {Function()} close 		日历关闭时触发			可定义页面关闭时的回调事件
	 * @example <e-calendar  :defaultDate="defaultDateMultiple" :show="show" mode="multiple" @confirm="confirm"></e-calendar>
	 * */
	export default defineComponent({
		name: 'e-calendar',
		mixins: [mpMixin]
	})
</script>
<script lang="ts" setup>
	import { ref, computed, onMounted, toRefs } from 'vue'
	import eHeader from './header.vue'
	import {
		useDefaultProps
	} from '../../libs/hooks'
	import { calendarProps, calendarEmits } from './props'
	import { isNumber, ListBetweenDates } from "../../libs/utils";
	import { throwError } from '../../libs/utils/_utils'
	import type { calendarMonthContext } from '../../libs/tokens'
	import componentsProps, {
		type DefaultProps
	} from "../../libs/config/componentsProps";


	const {
		calendar: calendarDefaultProps
	} = toRefs(componentsProps);

	const _props = defineProps(calendarProps)
	const props = useDefaultProps<DefaultProps['calendar']>(_props, calendarDefaultProps);
	const emit = defineEmits(calendarEmits)

	// let innerFormatter = (value: Date) => value




	// 由于maxDate和minDate可以为字符串(2021-10-10)，或者数值(时间戳)，但是dayjs如果接受字符串形式的时间戳会有问题，这里进行处理
	const innerMaxDate = computed(() => {
		return isNumber(props.value.maxDate)
			? props.value.maxDate
			: Number(props.value.maxDate)
	})
	const innerMinDate = computed(() => {
		return isNumber(props.value.minDate)
			? props.value.minDate
			: Number(props.value.minDate)
	})

	// month组件内部选择日期后，通过事件通知给父组件
	const monthSelected = (e : number[]) => {
		if (e.length) {
			if (
				props.value.mode === 'multiple' ||
				props.value.mode === 'single'
			) {
				emit('confirm', e)
			} else if (e.length >= 2 || e.length >= 1 && props.value.allowSameDay) {
				if (props.value.conversion) {
					emit('confirm', ListBetweenDates(new Date(e[0]), new Date(e[1])).map(item => item.getTime()))
				} else {
					emit('confirm', e)
				}
			}
		}

	}
	const init = () => {

		// 校验maxDate，不能小于当前时间
		if (
			innerMaxDate.value &&
			new Date(innerMaxDate.value).getTime() <= Date.now()
		) {
			return throwError('calendar', 'maxDate不能小于当前时间')
		}
	}
	const monthRef = ref<calendarMonthContext | null>(null)
	const monthChange = (type : string) => {
		if (type === 'pre') {
			monthRef.value?.toPreMonth()
		} else if (type === 'next') {
			monthRef.value?.toNextMonth()
		}else{
			monthRef.value?.setMonth(type)
		}
	}

	const myDate = ref(new Date())
	const changeMonth = (d : Date) => {
		myDate.value = d
		emit('monthChange', d)
	}






	onMounted(() => {
		init()
		changeMonth(myDate.value)
	})

// // 在微信小程序中，不支持将函数当做props参数，故只能通过ref形式调用
// const setFormatter = (e: (v: Date) => any) => {
// 	innerFormatter = e
// }

// defineExpose({
// 	/** @description set formatter value */
// 	setFormatter

// })
</script>

<style lang="scss" scoped>
	@import '../../libs/theme/calendar.scss';
</style>